/**
 * 
 */
package com.dalonedrow.rpg.base.flyweights;

import com.dalonedrow.utils.Watchable;
import com.dalonedrow.utils.Watcher;

/**
 * @author Donald
 */
public abstract class IONPCData<IO> implements Watchable {
	float				absorb;
	long				aiming_start;
	float				aimtime;
	float				armor_class;
	float				armorClass;
	float				backstab_skill;
	long				behavior;
	float				behavior_param;
	float				climb_count;
	long				collid_state;
	long				collid_time;
	float				critical;
	long				cut;
	short				cuts;
	float				damages;
	long				detect;
	float				fDetect;
	long				fightdecision;
	float				lastmouth;
	float				life;
	float				look_around_inc;
	long				ltemp;
	float				mana;
	float				maxlife;
	float				maxmana;

	long				movemode;
	float				moveproblem;
	/** the {@link IONPCData}'s name. */
	private char[]		name;
	/** all NPC flags. */
	private long		npcFlags;
	// IO_PATHFIND pathfind;
	// EERIE_EXTRA_ROTATE * ex_rotate;
	// D3DCOLOR blood_color;
	char				padd;
	// IO_BEHAVIOR_DATA stacked[MAX_STACKED_BEHAVIOR];
	float				poisonned;
	float				reach;
	long				reachedtarget;					// Is target in
														// REACHZONE ?
	long				reachedtime;
	char				resist_fire;
	char				resist_magic;
	char				resist_poison;
	float				speakpitch;
	private int			splatDamages;
	private int			splatTotNb;
	float				stare_factor;
	short				strike_time;

	long				tactics;						// 0=none ; 1=side ;
	// 2=side+back
	float				tohit;
	short				unused;
	// EERIE_3D last_splat_pos;
	float				vvpos;

	short				walk_start_time;
	/**
	 * the list of {@link Watcher}s associated with this {@link IONPCData}.
	 */
	private Watcher[]	watchers	= new Watcher[0];
	/** the NPC's weapon. */
	private IO			weapon;
	long				weaponinhand;
	char[]				weaponname	= new char[256];

	long				weapontype;
	int					xpvalue;
	/**
	 * Adds an NPC flag.
	 * @param flag the flag
	 */
	public final void addNPCFlag(final long flag) {
		npcFlags |= flag;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void addWatcher(final Watcher watcher) {
		int index = -1;
		for (int i = 0; i < watchers.length; i++) {
			if (watchers[i] == null) {
				index = i;
				break;
			}
		}
		if (index > -1) {
			watchers[index] = watcher;
		} else {
			Watcher[] dest = new Watcher[watchers.length + 1];
			System.arraycopy(watchers, 0, dest, 0, watchers.length);
			dest[watchers.length] = watcher;
			watchers = dest;
			dest = null;
		}
	}
	/** Clears all NPC flags that were set. */
	public final void clearNPCFlags() {
		npcFlags = 0;
	}
	/**
	 * Gets the armorClass
	 * @return {@link float}
	 */
	public float getArmorClass() {
		return armorClass;
	}
	/**
	 * Gets the {@link IONPCData}'s name.
	 * @return char[]
	 */
	public final char[] getName() {
		return name;
	}
	/**
	 * Gets the splatDamages
	 * @return {@link int}
	 */
	public int getSplatDamages() {
		return splatDamages;
	}
	/**
	 * Gets the splatTotNb
	 * @return {@link int}
	 */
	public int getSplatTotNb() {
		return splatTotNb;
	}
	/**
	 * Gets the NPC's weapon.
	 * @return {@link IO}
	 */
	public final IO getWeapon() {
		return weapon;
	}
	/**
	 * Determines if the {@link IONPCData} has a specific flag.
	 * @param flag the flag
	 * @return true if the {@link IONPCData} has the flag; false otherwise
	 */
	public final boolean hasNPCFlag(final long flag) {
		return (npcFlags & flag) == flag;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void notifyWatchers() {
		for (int i = 0; i < watchers.length; i++) {
			watchers[i].watchUpdated(this);
		}
	}
	/**
	 * Removes an NPC flag.
	 * @param flag the flag
	 */
	public final void removeNPCFlag(final long flag) {
		npcFlags &= ~flag;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void removeWatcher(final Watcher watcher) {
		int index = -1;
		for (int i = 0; i < watchers.length; i++) {
			if (watchers[i].equals(watcher)) {
				index = i;
				break;
			}
		}
		if (index == 0) {
			Watcher[] dest = new Watcher[watchers.length];
			System.arraycopy(watchers, 1, dest, 0, watchers.length);
			watchers = dest;
			dest = null;
		} else if (index > 0 && index < watchers.length - 1) {
			Watcher[] dest = new Watcher[watchers.length];
			System.arraycopy(watchers, 0, dest, 0, index);
			System.arraycopy(
					watchers, index + 1, dest, 0, watchers.length - 1 - index);
			watchers = dest;
			dest = null;
		} else if (index == watchers.length - 1) {
			Watcher[] dest = new Watcher[watchers.length];
			System.arraycopy(watchers, 0, dest, 0, watchers.length - 1);
			watchers = dest;
			dest = null;
		}
	}
	/**
	 * Sets the armorClass
	 * @param armorClass the armorClass to set
	 */
	public void setArmorClass(float armorClass) {
		this.armorClass = armorClass;
	}

	/**
	 * Sets the {@link IOPCData}'s name.
	 * @param val the name to set
	 */
	public final void setName(final char[] val) {
		name = val;
		notifyWatchers();
	}
	/**
	 * Sets the {@link IOPCData}'s name.
	 * @param val the name to set
	 */
	public final void setName(final String val) {
		name = val.toCharArray();
		notifyWatchers();
	}
	/**
	 * Sets the splatDamages
	 * @param splatDamages the splatDamages to set
	 */
	public void setSplatDamages(int val) {
		this.splatDamages = val;
	}
	/**
	 * Sets the splatTotNb
	 * @param splatTotNb the splatTotNb to set
	 */
	public void setSplatTotNb(int val) {
		this.splatTotNb = val;
	}
	/**
	 * Sets the NPC's weapon.
	 * @param io the weapon to set
	 */
	public final void setWeapon(final IO io) {
		weapon = io;
	}
}
